﻿using HostOptions = MicroCloud.AspNetCore.Host.Options.Host;
using EndpointOptions = MicroCloud.AspNetCore.Host.Options.Endpoint;

namespace MicroCloud.AspNetCore.Host
{
    /// <summary>
    /// Kestrel宿主配置扩展
    /// </summary>
    public static class Kestrel
    {
        /// <summary>
        /// 配置 Kestrel Host
        /// </summary>
        /// <param name="options">提供Kestrel特定功能的编程配置</param>
        /// <param name="optFunc">公共配置方法，不为 null 时执行自定义配置。</param>
        /// <param name="endpointAction">终结点配置方法，不为 null 时执行自定义配置。</param>
        public static void SetHost(this KestrelServerOptions options, Func<KestrelServerOptions, KestrelServerOptions> optFunc = null, Action<KestrelServerOptions, EndpointOptions> endpointAction = null)
        {
            // 注：Kestrel 的默认监听端口是 http:5000、https:5001。

            // 设置应用服务器 Kestrel 请求体最大值
            /* 获取或设置任何请求正文的最大允许大小（以字节为单位）。当设置为null时，最大请求正文大小不受限制。此限制对始终不受限制的升级连接没有影响。
             * 这可以通过<see cref=“Microsoft.AspNetCore.Http.Features.IHttpMaxRequestBodySizeFeature”/>按请求覆盖。默认值为30000000字节，约为28.6MB。 */
            options.Limits.MaxRequestBodySize = null;
            /* 获取或设置请求缓冲区的最大大小。默认值为1048576字节（1 MB）。当设置为null时，请求缓冲区的大小不受限制。 */
            options.Limits.MaxRequestBufferSize = null;
            /* 获取或设置在写入调用开始阻止或返回在缓冲区大小降至配置限制以下之前未完成的任务之前的响应缓冲区的最大大小。默认值为65536字节（64 KB）。
             * 当设置为null时，响应缓冲区的大小不受限制。当设置为零时，所有写调用都将阻止或返回在整个响应缓冲区被刷新之前未完成的任务。 */
            options.Limits.MaxResponseBufferSize = null;
            /* 获取或设置保持活动超时。默认为130秒。 */
            options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(10);
            /* 获取或设置服务器接收请求标头的最长时间。默认为30秒。 */
            options.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(120);

            if (optFunc != null)
            {
                options = optFunc(options);
            }

            //获取配置信息
            var configuration = options.ApplicationServices.GetService<IConfiguration>();
            //依据Host类反序列化appsettings.json中指定节点
            var host = configuration.GetSection("MicroCloud:Host").Get<HostOptions>();
            if (host != null)
            {
                foreach (var endpointKvp in host.Endpoints)
                {
                    var endpointName = endpointKvp.Key;
                    var endpoint = endpointKvp.Value;
                    if (!endpoint.Enabled)
                    {
                        continue;
                    }
                    if (endpoint.Address.IsMissing() || endpoint.Address == "*")
                    {
                        options.ListenAnyIP(endpoint.Port, opt =>
                       {
                           //证书不为空使用UserHttps
                           if (endpoint.SSL != null)
                           {
                               switch (endpoint.SSL.Source.ToLower())
                               {
                                   case "file":
                                       opt.UseHttps(endpoint.SSL.Path, endpoint.SSL.Password);
                                       break;
                                   default:
                                       throw new NotImplementedException(I18N.T("SSL证书源 {0} 功能未实现", endpoint.SSL.Source));
                               }
                           }
                       });
                    }
                    else
                    {
                        var address = IPAddress.Parse(endpoint.Address);
                        options.Listen(address, endpoint.Port, opt =>
                        {
                            //证书不为空使用UserHttps
                            if (endpoint.SSL != null)
                            {
                                switch (endpoint.SSL.Source.ToLower())
                                {
                                    case "file":
                                        opt.UseHttps(endpoint.SSL.Path, endpoint.SSL.Password);
                                        break;
                                    default:
                                        throw new NotImplementedException(I18N.T("SSL证书源 {0} 功能未实现", endpoint.SSL.Source));
                                }
                            }
                        });
                    }

                    endpointAction?.Invoke(options, endpoint);
                    options.UseSystemd();
                }
            }
        }

    }

}